home *** CD-ROM | disk | FTP | other *** search
- /*
- * bdy.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /*
- * BDY.C
- *
- * functions implementating C.T.Zahn's algorithm for boundary
- * detection and representation
- *
- */
- #include <stdio.h>
- #include <malloc.h>
- #include <stdlib.h>
- #include <math.h>
- #include "ip.h"
- #include "bdy.h"
-
- #define WINDOW_ROWS 3
- #define NDIRECTIONS 8
-
- #define THRESH 1
- #define MIN_POLY_SIZE 1
- #define ZERO 0
- #define ROOT2 1.414213562
-
- #define ON 1
- #define OFF 0
- #undef SHOW_CURV_PT
-
- #define RESET ON
-
- #define IN_LIST 1
- #define OUT_LIST 0
- #define SHOW_CURV_PT
-
-
- /* global variables */
- extern struct curv_points *curv_head_in[NDIRECTIONS];
- extern struct curv_points *curv_head_out[NDIRECTIONS];
- extern struct curv_points *curv_tail_in[NDIRECTIONS];
- extern struct curv_points *curv_tail_out[NDIRECTIONS];
-
- extern struct polygon *poly_head_ptr;
- extern struct polygon *poly_tail_ptr;
-
- extern float *delta_phik, *delta_lk;
- extern long ncp;
-
- unsigned int d1, d2, d3, d4, d5, d6, b1, b2, b3, b4, b5, b6;
- unsigned nbytes = 1;
-
-
- /*
- * generate curvature points using Zahn algorithm
- * (ref: C. T. Zahn, SLAC report No. 70, Dec. 1966)
- */
- void
- curvature_points (unsigned char *window[], int ir, int jmax, int imax)
- {
- int jc;
-
- for (jc = 0; jc < jmax - 2; jc++) {
- d1 = *(*(window + (ir % WINDOW_ROWS)) + jc);
- d2 = *(*(window + (ir % WINDOW_ROWS)) + jc + 1);
- d3 = *(*(window + (ir % WINDOW_ROWS)) + jc + 2);
- d4 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc);
- d5 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 1);
- d6 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 2);
- horizontal (ir, jc);
- }
- for (jc = 0; jc < jmax - 1; jc++) {
- b1 = *(*(window + (ir % WINDOW_ROWS)) + jc + 1);
- b2 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 1);
- b3 = *(*(window + ((ir + 2) % WINDOW_ROWS)) + jc + 1);
- b4 = *(*(window + (ir % WINDOW_ROWS)) + jc);
- b5 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc);
- b6 = *(*(window + ((ir + 2) % WINDOW_ROWS)) + jc);
- vertical (ir, jc);
- }
- if (ir == imax - WINDOW_ROWS) {
- ir++;
- for (jc = 0; jc < jmax - 2; jc++) {
- d1 = *(*(window + (ir % WINDOW_ROWS)) + jc);
- d2 = *(*(window + (ir % WINDOW_ROWS)) + jc + 1);
- d3 = *(*(window + (ir % WINDOW_ROWS)) + jc + 2);
- d4 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc);
- d5 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 1);
- d6 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 2);
- horizontal (ir, jc);
- }
- }
- }
-
-
- /*
- * check 3x2 horizontal array (in a binary image) and determine
- * direction codes for incoming and outgoing contour segment
- */
- int
- horizontal (i, j)
- int i, j;
- {
- int in, out;
- int err_flag = -1;
-
- if (d2 >= THRESH) {
- if (d5 == ZERO) {
- if (d6 >= THRESH)
- in = 3;
- else if (d3 >= THRESH)
- in = 4;
- else
- in = 5;
-
- if (d4 >= THRESH)
- out = 5;
- else if (d1 >= THRESH)
- out = 4;
- else
- out = 3;
- }
- else
- return (err_flag);
- }
- else {
- if (d5 >= THRESH) {
- if (d1 >= THRESH)
- in = 7;
- else if (d4 >= THRESH)
- in = 0;
- else
- in = 1;
-
- if (d3 >= THRESH)
- out = 1;
- else if (d6 >= THRESH)
- out = 0;
- else
- out = 7;
- }
- else
- return (err_flag);
- }
-
- /*
- * curvature point found!
- * allocate memory and store it in linked list curv_points structure
- */
- if (in != out) {
-
- #ifdef SHOW_CURV_PT
- printf (" horizontal: ir= %d, jc= %d, in= %d, out= %d\n",
- 2 * (i + 1), 2 * (j + 1) + 1, in, out);
- #endif
- if (curv_head_in[in] == NULL) {
- curv_head_in[in] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_head_in[in]->prev = NULL;
- curv_tail_in[in] = curv_head_in[in];
- }
- else {
- curv_tail_in[in]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_tail_in[in]->next->prev = curv_tail_in[in];
- curv_tail_in[in] = curv_tail_in[in]->next;
- }
- if (curv_head_out[out] == NULL) {
- curv_head_out[out] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_head_out[out]->prev = NULL;
- curv_tail_out[out] = curv_head_out[out];
- }
- else {
- curv_tail_out[out]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_tail_out[out]->next->prev = curv_tail_out[out];
- curv_tail_out[out] = curv_tail_out[out]->next;
- }
- ncp++;
-
- curv_tail_in[in]->same_point = curv_tail_out[out];
- curv_tail_in[in]->next = NULL;
- curv_tail_out[out]->next = NULL;
- curv_tail_in[in]->xn = curv_tail_out[out]->xn = 2 * (j + 1) + 1;
- curv_tail_in[in]->yn = curv_tail_out[out]->yn = 2 * (i + 1);
- curv_tail_in[in]->edge_in = curv_tail_out[out]->edge_in = in;
- curv_tail_in[in]->edge_out = curv_tail_out[out]->edge_out = out;
- }
- return (1);
- }
-
-
- /*
- * check 2x3 vertical array (in a binary image) and determine
- * direction codes for incoming and outgoing contour segment
- */
- int
- vertical (i, j)
- int i, j;
- {
- int in, out;
- int err_flag = -1;
-
- if (b2 >= THRESH) {
- if (b5 == ZERO) {
- if (b6 >= THRESH)
- in = 1;
- else if (b3 >= THRESH)
- in = 2;
- else
- in = 3;
-
- if (b4 >= THRESH)
- out = 3;
- else if (b1 >= THRESH)
- out = 2;
- else
- out = 1;
- }
- else
- return (err_flag);
- }
- else {
- if (b5 >= THRESH) {
- if (b1 >= THRESH)
- in = 5;
- else if (b4 >= THRESH)
- in = 6;
- else
- in = 7;
-
- if (b3 >= THRESH)
- out = 7;
- else if (b6 >= THRESH)
- out = 6;
- else
- out = 5;
- }
- else
- return (err_flag);
- }
-
- /*
- * curvature point found!
- * allocate memory and store it in linked list curv_points structure
- */
- if (in != out) {
-
- #ifdef SHOW_CURV_PT
- printf (" vertical: ir= %d, jc= %d, in= %d, out= %d\n",
- 2 * (i + 1) + 1, 2 * (j + 1), in, out);
- #endif
-
- if (curv_head_in[in] == NULL) {
- curv_head_in[in] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_head_in[in]->prev = NULL;
- curv_tail_in[in] = curv_head_in[in];
- }
- else {
- curv_tail_in[in]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_tail_in[in]->next->prev = curv_tail_in[in];
- curv_tail_in[in] = curv_tail_in[in]->next;
- }
- if (curv_head_out[out] == NULL) {
- curv_head_out[out] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_head_out[out]->prev = NULL;
- curv_tail_out[out] = curv_head_out[out];
- }
- else {
- curv_tail_out[out]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
- curv_tail_out[out]->next->prev = curv_tail_out[out];
- curv_tail_out[out] = curv_tail_out[out]->next;
- }
- ncp++;
-
- curv_tail_in[in]->same_point = curv_tail_out[out];
- curv_tail_in[in]->next = NULL;
- curv_tail_out[out]->next = NULL;
- curv_tail_in[in]->xn = curv_tail_out[out]->xn = 2 * (j + 1);
- curv_tail_in[in]->yn = curv_tail_out[out]->yn = 2 * (i + 1) + 1;
- curv_tail_in[in]->edge_in = curv_tail_out[out]->edge_in = in;
- curv_tail_in[in]->edge_out = curv_tail_out[out]->edge_out = out;
- }
- return (1);
- }
-
-
- /*
- * link up all curvature points into closed polygons
- */
- void
- linkage (Image * imgIn, Image * imgOut, int value)
- {
- struct polygon *dummy_poly_ptr;
- struct curv_points *first_point;
- float *d_phi_head, *d_l_head;
- int m, c;
- char inbuf[IN_BUF_LEN];
-
- do {
- d_phi_head = delta_phik;
- d_l_head = delta_lk;
- for (m = 0; m < NDIRECTIONS; m++)
- if ((first_point = curv_head_out[m]) != NULL) {
- poly (first_point);
- break;
- }
- } while (first_point != NULL);
-
- if (ncp != 0)
- printf ("...something wrong, didn't find all polygons!\n");
- if (poly_head_ptr == NULL) {
- printf ("...no objects found to analyze!\n");
- return;
- }
-
- /*
- * polygon analysis
- */
- printf ("...generate curvature points for polygons?(y/n) -- ");
- while ((c = readlin (inbuf)) == 'y') {
- dummy_poly_ptr = select_poly (poly_head_ptr, imgOut, value);
- printf ("\n...generate curvature points for another polygon?(y/n)");
- }
- }
-
- /*
- * create a closed polygon given a starting curvature point
- */
- void
- poly (first_point)
- struct curv_points *first_point;
- {
- struct curv_points *next_point, *prev_point, *match_in_list ();
-
- if (poly_head_ptr == NULL) {
- poly_head_ptr = (struct polygon *) calloc (nbytes, sizeof (struct polygon));
- poly_tail_ptr = poly_head_ptr;
- poly_head_ptr->prev_poly = NULL;
- }
- else {
- poly_tail_ptr->next_poly = (struct polygon *) calloc (nbytes, sizeof (struct polygon));
- poly_tail_ptr->next_poly->prev_poly = poly_tail_ptr;
- poly_tail_ptr = poly_tail_ptr->next_poly;
- }
- poly_tail_ptr->next_poly = NULL;
-
- prev_point = first_point;
- next_point = match_in_list (prev_point);
- poly_tail_ptr->d_phi_ptr = delta_phik;
- poly_tail_ptr->d_l_ptr = delta_lk;
- poly_tail_ptr->poly_points = 0;
- poly_tail_ptr->total_delta_phi = (float) 0;
- poly_tail_ptr->first_x = first_point->xn;
- poly_tail_ptr->first_y = first_point->yn;
- poly_tail_ptr->first_edge_out = first_point->edge_out;
- create_edge (prev_point, next_point);
- delete_list (prev_point, OUT_LIST);
- prev_point = next_point->same_point;
- delete_list (next_point, IN_LIST);
- ncp--;
- poly_tail_ptr->poly_points++;
- poly_tail_ptr->total_delta_phi = poly_tail_ptr->total_delta_phi + *delta_phik;
- delta_lk++;
- delta_phik++;
- do {
- next_point = match_in_list (prev_point);
- create_edge (prev_point, next_point);
- delete_list (prev_point, OUT_LIST);
- prev_point = next_point->same_point;
- delete_list (next_point, IN_LIST);
- ncp--;
- poly_tail_ptr->poly_points++;
- poly_tail_ptr->total_delta_phi = poly_tail_ptr->total_delta_phi
- + *delta_phik;
- delta_lk++;
- delta_phik++;
-
- if (ncp < 0) {
- printf ("Something wrong, points<0\n");
- exit (1);
- }
- }
- while (prev_point != first_point);
-
- if (poly_tail_ptr->poly_points <= MIN_POLY_SIZE) {
- if (poly_tail_ptr->prev_poly == NULL)
- poly_head_ptr = NULL;
- else {
- poly_tail_ptr = poly_tail_ptr->prev_poly;
- free (poly_tail_ptr->next_poly);
- poly_tail_ptr->next_poly = NULL;
- }
- }
- }
-
- /*
- * given a point in the out-list, find the next point
- * in the in-list with edge-out(out-list) = edge-in(in-list)
- */
- struct curv_points *
- match_in_list (current_point)
- struct curv_points *current_point;
- {
- struct curv_points *tail_point, *head_point;
- int direction;
- int xcurr, ycurr, xnext, ynext;
-
- xcurr = current_point->xn;
- ycurr = current_point->yn;
- printf ("match_in_list: current point = (%d, %d)\n", xcurr, ycurr);
- direction = current_point->edge_out;
- tail_point = curv_tail_in[direction];
- head_point = curv_head_in[direction];
- while ((head_point != NULL) || (tail_point != NULL)) {
- switch (direction) {
- case 0:
- ynext = head_point->yn;
- xnext = head_point->xn;
- if ((ycurr == ynext) && (xnext > xcurr))
- return (head_point);
- break;
- case 4:
- ynext = tail_point->yn;
- xnext = tail_point->xn;
- if ((ycurr == ynext) && (xnext < xcurr))
- return (tail_point);
- break;
- case 2:
- ynext = tail_point->yn;
- xnext = tail_point->xn;
- if ((xcurr == xnext) && (ynext < ycurr))
- return (tail_point);
- break;
- case 6:
- ynext = head_point->yn;
- xnext = head_point->xn;
- if ((xcurr == xnext) && (ynext > ycurr))
- return (head_point);
- break;
- case 1:
- ynext = tail_point->yn;
- xnext = tail_point->xn;
- if (((xcurr + ycurr) == (xnext + ynext)) &&
- (xnext > xcurr) && (ynext < ycurr))
- return (tail_point);
- break;
- case 5:
- ynext = head_point->yn;
- xnext = head_point->xn;
- if (((xcurr + ycurr) == (xnext + ynext)) &&
- (xnext < xcurr) && (ynext > ycurr))
- return (head_point);
- break;
- case 3:
- ynext = tail_point->yn;
- xnext = tail_point->xn;
- if (((xcurr - ycurr) == (xnext - ynext)) &&
- (xnext < xcurr) && (ynext < ycurr))
- return (tail_point);
- break;
- case 7:
- ynext = head_point->yn;
- xnext = head_point->xn;
- if (((xcurr - ycurr) == (xnext - ynext)) &&
- (xnext > xcurr) && (ynext > ycurr))
- return (head_point);
- break;
- }
- tail_point = tail_point->prev;
- head_point = head_point->next;
- }
- printf ("...no match found in outlist[%d]\n", direction);
- exit (1);
- }
-
- /*
- * delete curvature point from either in-list or out-list
- */
- void
- delete_list (current_point, list)
- struct curv_points *current_point;
- int list;
- {
- int direction;
-
- if (current_point == NULL)
- printf ("...current point can't be NULL!\n");
-
- if ((current_point->prev == NULL) && (current_point->next == NULL)) {
- if (list == IN_LIST) {
- direction = current_point->edge_in;
- curv_head_in[direction] = NULL;
- curv_tail_in[direction] = NULL;
- }
- else {
- direction = current_point->edge_out;
- curv_head_out[direction] = NULL;
- curv_tail_out[direction] = NULL;
- }
- }
- else if (current_point->prev == NULL) {
- if (list == IN_LIST) {
- direction = current_point->edge_in;
- curv_head_in[direction] = current_point->next;
- }
- else {
- direction = current_point->edge_out;
- curv_head_out[direction] = current_point->next;
- }
- current_point->next->prev = NULL;
- }
- else if (current_point->next == NULL) {
- if (list == IN_LIST) {
- direction = current_point->edge_in;
- curv_tail_in[direction] = current_point->prev;
- }
- else {
- direction = current_point->edge_out;
- curv_tail_out[direction] = current_point->prev;
- }
- current_point->prev->next = NULL;
- }
- else {
- current_point->prev->next = current_point->next;
- current_point->next->prev = current_point->prev;
- }
- free (current_point);
- }
-
-
- void
- print_curv ()
- {
- int x, y;
- struct curv_points *temp_head;
-
- for (x = 0; x < NDIRECTIONS; x++) {
- y = 0;
- temp_head = curv_head_in[x];
- while (temp_head != NULL) {
- y++;
- temp_head = temp_head->next;
- }
- if (y != 0)
- printf ("inlist[%d] = %d\n", x, y);
- }
-
- for (x = 0; x < NDIRECTIONS; x++) {
- y = 0;
- temp_head = curv_head_out[x];
- while (temp_head != NULL) {
- y++;
- temp_head = temp_head->next;
- }
- if (y != 0)
- printf ("outlist[%d] = %d\n", x, y);
- }
- }
-
-
- /*
- * create an edge from old-point to new-point
- */
- void
- create_edge (old_point, new_point)
- struct curv_points *old_point, *new_point;
- {
- int phi;
-
- switch (new_point->edge_in) {
- case 0:
- case 4:
- *delta_lk = (float) abs (new_point->xn - old_point->xn);
- phi = new_point->edge_out - new_point->edge_in;
- if (phi == 7)
- phi = -1;
- *delta_phik = (float) phi;
- break;
- case 2:
- case 6:
- *delta_lk = (float) abs (new_point->yn - old_point->yn);
- *delta_phik = (float) (new_point->edge_out - new_point->edge_in);
- break;
- default:
- *delta_lk = (float) abs (new_point->xn - old_point->xn) * (float) ROOT2;
- phi = new_point->edge_out - new_point->edge_in;
- if (phi == -7)
- phi = 1;
- else if (phi == -6)
- phi = 2;
- else if (phi == 6)
- phi = -2;
- *delta_phik = (float) phi;
- break;
- }
- }
-